[scautoloc] Add location-dependent depth lookup (Slab2 backend)#126
[scautoloc] Add location-dependent depth lookup (Slab2 backend)#126comoglu wants to merge 12 commits into
Conversation
Replace fixed locator.defaultDepth and autoloc.maxDepth with a
geographic DepthLookup system compiled directly into scautoloc.
No plugin loader, no Client::Application dependency — safe to use
from standalone code and Python scripts.
Backends (selected via autoloc.depthLookup):
Constant (default) — uses existing defaultDepth/maxDepth config
values unchanged; zero behaviour change for
existing deployments
Slab2 — USGS Slab2.0 depth-footprint contours; depth
and maxDepth vary by geographic location
Config:
autoloc.depthLookup = Constant | Slab2
autoloc.slab2.directory = path to BNA contour files
- Add 531 USGS Slab2.0 depth-contour BNA files (35 depth levels, 27 slab zones) installed to share/scautoloc/slabs/ - Update config.cpp dump() to show depthLookup type and slabDir - Update scautoloc.xml with depthLookup and slab2.directory params
- Fix feature name to match BNA header format: 'zone depth km' - Initialize _depthLookup in constructor to prevent null dereference if init() is bypassed or fails early - Use Environment::absolutePath(configGetString()) for slabDir, consistent with gridConfigFile/staConfFile pattern
Use Environment::shareDir() in catch block so the default slabs path is correctly resolved even when autoloc.slab2.directory is not explicitly configured.
Two bugs fixed: - BNA files had negative vertex counts (-N) which SC's GeoFeature treats as open polygons (closedPolygon=false), making contains() always return false. Changed to positive counts so polygons are loaded as closed and contains() works correctly. - _lookupDepth/_fetchMaxDepth: check all sub-polygons per zone level (some zones have multiple sub-polygons with the same name).
- Rename _dd → dd and _maxDep → maxDep (leading underscore is for class members only, not local variables) - Fix typo: "objects(s)" → "object(s)"
Adds fetchCandidateDepths() to the DepthLookup interface (default wraps
fetch(), returns single depth — existing behaviour unchanged).
Slab2 backend overrides it: inside a slab zone returns {slabDepth,
fallbackDepth} so both the deep slab seed and the shallow crustal seed
are evaluated. Outside all zones returns {fallbackDepth} as before.
_setDefaultDepth() now iterates all candidates and keeps the
best-scoring relocation, enabling correct depth assignment in regions
with dual seismicity (e.g. Tonga: 140 km slab vs 10 km crustal).
| AutolocInternal::OriginVector _origins; | ||
| AutolocConfig _config; | ||
| AutolocInternal::StationConfig _stationConfig; | ||
| DepthLookupPtr _depthLookup; |
There was a problem hiding this comment.
There is one DepthLookup. That would mean that scautoloc can use either DepthLookupPolygon or Slab2DepthLookup, right? But what if it needs to use both? The common use case is: Slabs in subduction zones but also regions which only have induced seismicity where I need to fix the depth to a regional default no matter what. Or think of ocean ridges and transform faults, where the value DepthLookupPolygon would be that I can specify explicitly "for this region fix the depth and don't try different depths". Currently there is a default depth but scautoloc always performs some tests to see if an event could be deeper. And occasionally the result is wrong, e.g. if an event at a mid-ocean ridge is located at 120 km depth. DepthLookupPolygon can prevent that very effectively. But ideally not at the expense of Slab2DepthLookup.
There was a problem hiding this comment.
The idea of the DepthLookup is to outsource that knowledge. If you need a version of DepthLookup with all your special code paths then implement an DepthLookupAutoloc which internally instantiates both classes and does all the processing. scautoloc should just query one interface regardless of the implementation. Think of it as a RecordStream.
There was a problem hiding this comment.
Hi @gempa-jabe
This makes perfect sense, so a DepthLookupComposite (or whatever we call it) in seiscomp/common internally combines Polygon + Slab2 + Constant with priority ordering. scautoloc just queries one interface and doesn't care what's underneath.
That also means Slab2 should move to common, which is what @jsaul was asking for.
One thing I want to flag @jsaul before I start working on it, the original reason I kept it self-contained in scautoloc was @jsaul 's goal of calling autoloc from Python/ObsPy without the full SC environment. Moving to the factory + init(Config::Config&) pattern brings that dependency back in. Is that still a concern, or has that goal changed?
There was a problem hiding this comment.
Don't get on it too fast. I am not saying that we need to implement everything in common. I am saying that the strength of the DepthLookup interface is that we are able to remove the complexity of that operation from the client. Having that said, stick to the current implementation in common and add everything needed here to get a proof of concept. I know that an implementation change is just one Claude prompt away but doing that in common is wrong at this stage. The interface is there, two simple example implementations are there and more complex stuff can be added later once proven its usefulness. Please learn your lessons with scautoloc first.
There was a problem hiding this comment.
Noted, will hold off and will work on proving the concept in scautoloc first. Thanks, @gempa-jabe .
There was a problem hiding this comment.
There are several misunderstandings involved and I think we should not discuss everything here on Github (i.e. in public).
Anyway, the Slab2DepthLookup should not be provided through scautoloc. Doesn't have to be in common either, could also be under https://github.com/comoglu - as long as it remains installable. That's the advantage of making it a plugin and not a library function.
There was a problem hiding this comment.
@jsaul @gempa-jabe
There are now two new repos.
https://github.com/comoglu/seiscomp-slab2-plugin
https://github.com/comoglu/main/tree/feature/depthlookup-factory
[ https://github.com//pull/127 ] Draft
Polygon backend queries named GeoFeature regions from the global GeoFeatureSet. Each region carries a defaultDepth attribute (required) and optionally maxDepth. covers() returns true only when the epicenter is inside a named polygon, so it acts as an explicit override layer. Composite backend chains backends in priority order — Polygon first, then Slab2, then Constant — delegating all three methods (fetch, fetchMaxDepth, fetchCandidateDepths) to the first backend where covers() returns true. covers() added to DepthLookup base (default true); Polygon and Slab2 override it to signal positive identification vs fallback. Config: autoloc.depthLookup = Composite autoloc.polygon.regions = induced_seismicity_zone, mid_ocean_ridges autoloc.slab2.directory = @datadir@/scautoloc/slabs
|
Just to clarify what those two repos are: The plugin repo (seiscomp-slab2-plugin) is a standalone SeisComP plugin that implements the DepthLookup interface from common PR #199. It registers a "Slab2" backend that reads USGS Slab2.0 BNA files from share/spatial/vector/slab2 (the same path scolv uses for display, so no duplicate data). I've tested it with live global traffic and depth lookups are firing correctly, e.g Philippines 80 km, Kuril 40 km etc. The feature/depthlookup-factory branch (Draft PR #127) is the scautoloc side : it replaces the compiled-in depth logic with DepthLookupFactory::Create() so any registered plugin can be loaded at runtime. There's one new config key autoloc.depthLookup which defaults to "Constant", meaning zero behaviour change if the plugin isn't loaded. The two are independent. The plugin can work with any module that supports the DepthLookup interface. The scautoloc PR only becomes relevant once you guys are happy with the interface design. |
Summary
Adds location-dependent
defaultDepthandmaxDepthto scautoloc via asmall abstract
DepthLookupinterface compiled directly into the binary.Two backends ship:
autoloc.defaultDepth/autoloc.maxDepth. This is the default; existing behaviour is unchanged.(BNA, 27 slab zones, 35 depth levels at 20 km intervals, 000–680 km).
The implementation is intentionally self-contained: no plugin loader, no
Client::Applicationdependency. Safe for standalone use and Python scripts.New config keys
New files
apps/processing/scautoloc/depthlookup.happs/processing/scautoloc/depthlookup.cppapps/processing/scautoloc/share/slabs/Integration points in autoloc.cpp
All
_config.defaultDepthcall sites replaced by_depthLookup->fetch(lat, lon);all
_config.maxDepthchecks replaced by_depthLookup->fetchMaxDepth(lat, lon).Test results (4 pick files, 2026-06-05)
With
Slab2vsConstant:Relationship to seiscomp/common PR #199
SeisComP/common#199 (
Seiscomp::Seismology::DepthLookup) provides anabstract factory interface for other SC modules. This PR is independent —
scautoloc's interface lives in
Seiscomp::Processingand has no dependencyon the common factory system. The two can coexist; a Slab2 plugin for the
common interface can be added separately if desired.